Skip to content

Infrastructure updates and cleanup#604

Merged
forstmeier merged 3 commits intomasterfrom
06-21-infrastructure_updates_and_cleanup
Jun 30, 2025
Merged

Infrastructure updates and cleanup#604
forstmeier merged 3 commits intomasterfrom
06-21-infrastructure_updates_and_cleanup

Conversation

@forstmeier
Copy link
Copy Markdown
Collaborator

@forstmeier forstmeier commented Jun 22, 2025

f# Overview

Changes

  • add back Mise infrastructure commands to fix GitHub deployment workflows
  • introduce Pulumi.production.yaml for production stack (replacing infrastructure)
  • unify various environment variable names

Comments

A couple things on this:

  1. I've updated the Pulumi project and stack namespace so we can have other stacks if we need it later
  2. I've launched this under the pocketizefund project in GCP due to permissioning and to cleanup naming
  3. I've regenerated Pulumi secrets and can share that file with you
  4. We'll need to deprecate the existing pocketsizefund-data bucket and move that to the pocketsizefund project due to naming collision (currently using a temporary name to avoid it)
  5. Merging to master to test the deploy workflow has not been done yet
  6. I tore down several obsolete stacks in Pulumi but ran into issues on a few due to missing resources and other things so that's outstanding cleanup

Summary by CodeRabbit

  • New Features

    • Introduced the "eventtrigger" service, providing a FastAPI application with endpoints for triggering scheduled events and health checks.
    • Added Cloud Scheduler jobs for automated event triggering, replacing previous Pub/Sub-based mechanisms.
    • Added GCP Monitoring email notification channels based on secret email lists.
  • Improvements

    • Standardized and updated environment variable names across services for consistency.
    • Expanded infrastructure to include new services: position manager, prediction engine, and event trigger.
    • Enhanced Prometheus metrics instrumentation for new and existing services.
    • Improved Docker and deployment workflows for infrastructure management.
  • Bug Fixes

    • Corrected environment variable usage and naming in configuration files and service definitions.
  • Refactor

    • Replaced external "category-encoders" dependency with an internal OrdinalEncoder implementation.
    • Updated function and parameter names for clarity and consistency.
    • Removed Prometheus and Grafana Cloud Run deployments in favor of GCP-native monitoring.
  • Tests

    • Added comprehensive unit tests for the new "eventtrigger" service and updated tests for internal encoder usage.
  • Chores

    • Updated project metadata, dependencies, and workspace configuration to include the new service and dependencies.
    • Cleaned up unused files and adjusted ignore rules.
  • Revert

    • Removed Pub/Sub topic and Prometheus configuration files no longer in use.

Copilot AI review requested due to automatic review settings June 22, 2025 03:18
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 22, 2025

Caution

Review failed

The pull request is closed.

## Walkthrough

This update standardizes environment variable naming across infrastructure and application components, updates Pulumi and Docker credential references, and improves automation scripts for infrastructure deployment and teardown. It also modifies project metadata, updates `.gitignore`, introduces new services and Cloud Scheduler jobs, removes Prometheus and Grafana monitoring infrastructure, and adds a new teardown task in the automation configuration.

## Changes

| Files/Paths                                                                                                   | Change Summary                                                                                                                  |
|--------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| `.github/workflows/lifecycle.yaml`, `.mise.toml`                                                             | Simplified lifecycle workflow to single-line `mise tasks run` commands; added `infrastructure:down` task with explicit stack.   |
| `.gitignore`                                                                                                  | Added `infrastructure/Pulumi.production.yaml` to ignore; removed `todos.md` from ignore list.                                    |
| `infrastructure/environment_variables.py`, `infrastructure/__main__.py`, `application/datamanager/compose.yaml`,<br>`application/datamanager/src/datamanager/config.py`, `infrastructure/buckets.py` | Renamed environment variables and secret keys for consistency (e.g., `DATA_BUCKET``DATA_BUCKET_NAME`, Alpaca and DuckDB keys). |
| `infrastructure/services.py`                                                                                  | Renamed parameter `envs` to `environment_variables`; added `enable_prometheus` flag; updated Docker Hub credential keys to uppercase. |
| `infrastructure/Pulumi.yaml`                                                                                  | Renamed Pulumi project and updated description capitalization.                                                                   |
| `infrastructure/__main__.py`                                                                                   | Added new services: `positionmanager`, `predictionengine`, `eventtrigger`; replaced Pub/Sub with Cloud Scheduler jobs; updated exports and environment variables. |
| `application/eventtrigger/` (Dockerfile, pyproject.toml, src/eventtrigger/)                                   | Added new FastAPI-based `eventtrigger` service with `/health` and `/trigger` endpoints handling specific event types.            |
| `application/eventtrigger/tests/test_eventtrigger_main.py`                                                    | Added unit tests for `eventtrigger` endpoints including success and error scenarios.                                              |
| `application/positionmanager/src/positionmanager/main.py`, `portfolio.py`                                     | Renamed parameter `data` to `historical_data` in portfolio optimizer method and call.                                            |
| `application/predictionengine/compose.yaml`, `pyproject.toml`, `src/predictionengine/dataset.py`, `main.py`, `post_processor.py`, `tests/test_post_processor.py`, `miniature_temporal_fusion_transformer.py` | Replaced external `category_encoders` dependency with internal `OrdinalEncoder` implementation; updated dependencies; simplified prediction logic to send average prices; added new env var `POSITIONMANAGER_BASE_URL`. |
| `infrastructure/monitoring.py`, `infrastructure/project.py`                                                  | Removed Prometheus and Grafana Cloud Run services and config; added GCP Monitoring NotificationChannels from secret emails; added new GCP services (Cloud Build, Monitoring, Cloud Scheduler). |
| `infrastructure/prometheus.yaml`, `infrastructure/topics.py`                                                 | Removed Prometheus config YAML and Pub/Sub topic resource.                                                                       |
| `pyproject.toml`                                                                                              | Added `application/eventtrigger` workspace member and test path; added lint ignore for predictionengine main.py.                  |
| `workflows/fetch_data.py`                                                                                     | Changed default GCP project from `fund-alpha` to `pocketsizefund` for service URL fetching.                                       |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant GitHub Actions
    participant mise
    participant Pulumi

    GitHub Actions->>mise: Run "infrastructure:up" or "infrastructure:down"
    mise->>Pulumi: Execute pulumi up/down with stack specification
    Pulumi-->>mise: Deploy or teardown infrastructure
    mise-->>GitHub Actions: Report result
sequenceDiagram
    participant Cloud Scheduler
    participant EventTrigger Service
    participant DataManager Service
    participant PredictionEngine Service
    participant PositionManager Service

    Cloud Scheduler->>EventTrigger Service: POST /trigger {event: fetch_data}
    EventTrigger Service->>DataManager Service: POST /equity-bars with date
    Cloud Scheduler->>EventTrigger Service: POST /trigger {event: create_positions}
    EventTrigger Service->>PredictionEngine Service: POST /create-positions
    Cloud Scheduler->>EventTrigger Service: POST /trigger {event: close_positions}
    EventTrigger Service->>PositionManager Service: DELETE /positions
Loading

Possibly related PRs

Suggested reviewers

  • chrisaddy

Poem

🐇 Through code and clouds I swiftly hop,
Names aligned, no more a flop.
Services new, and jobs that run,
Infrastructure up and down, all done!
Secrets kept and metrics shown,
In this field of bits I've grown.
Deploy with joy — the rabbit's song! 🎶✨


<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c8eb6a37f4bfe08ec01a04da3d85a1ee4646f5c4 and a93307ef0a0c8ccd990ca5312ff07265e1d167a0.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `uv.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (24)</summary>

* `application/eventtrigger/Dockerfile` (1 hunks)
* `application/eventtrigger/pyproject.toml` (1 hunks)
* `application/eventtrigger/src/eventtrigger/main.py` (1 hunks)
* `application/eventtrigger/src/eventtrigger/models.py` (1 hunks)
* `application/eventtrigger/tests/test_eventtrigger_main.py` (1 hunks)
* `application/positionmanager/src/positionmanager/main.py` (1 hunks)
* `application/positionmanager/src/positionmanager/portfolio.py` (1 hunks)
* `application/predictionengine/compose.yaml` (2 hunks)
* `application/predictionengine/pyproject.toml` (1 hunks)
* `application/predictionengine/src/predictionengine/dataset.py` (2 hunks)
* `application/predictionengine/src/predictionengine/main.py` (6 hunks)
* `application/predictionengine/src/predictionengine/miniature_temporal_fusion_transformer.py` (2 hunks)
* `application/predictionengine/src/predictionengine/post_processor.py` (2 hunks)
* `application/predictionengine/tests/test_post_processor.py` (4 hunks)
* `infrastructure/__main__.py` (1 hunks)
* `infrastructure/buckets.py` (2 hunks)
* `infrastructure/monitoring.py` (2 hunks)
* `infrastructure/project.py` (2 hunks)
* `infrastructure/prometheus.yaml` (0 hunks)
* `infrastructure/pyproject.toml` (1 hunks)
* `infrastructure/services.py` (3 hunks)
* `infrastructure/topics.py` (0 hunks)
* `pyproject.toml` (3 hunks)
* `workflows/fetch_data.py` (1 hunks)

</details>

</details>
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=pocketsizefund/pocketsizefund&utm_content=604):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request updates environment variable names and configuration settings to enforce a consistent naming convention across the infrastructure and application code. Key changes include updating DockerHub credential keys to uppercase, renaming various environment variables (e.g. ALPACA_API_KEY, DATA_BUCKET_NAME) for clarity, and modifying deployment commands to use explicit stack references.

Reviewed Changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
infrastructure/services.py Updated DockerHub credentials to use uppercase secret names
infrastructure/environment_variables.py Renamed environment variables for consistency (ALPACA, DUCKDB, DATA_BUCKET)
infrastructure/buckets.py Renamed bucket variable from production_data_bucket to data_bucket
infrastructure/main.py Updated environment variable references in service creation
infrastructure/Pulumi.yaml Changed project name and description for consistency
application/datamanager/src/datamanager/config.py Updated default environment variable key and error message in Bucket model
application/datamanager/compose.yaml Changed environment variable reference to DATA_BUCKET_NAME
.mise.toml Updated pulumi commands to use explicit stack names
.github/workflows/lifecycle.yaml Updated workflow commands to use mise tasks for stack operations
Comments suppressed due to low confidence (6)

infrastructure/services.py:53

  • Ensure that updating DockerHub secret names to uppercase aligns with deployment configurations and documentation.
                username=config.require_secret("DOCKERHUB_USERNAME"),

infrastructure/environment_variables.py:22

  • The variable name change to ALPACA_API_KEY improves clarity; verify that corresponding service configurations are updated accordingly.
ALPACA_API_KEY = create_environment_variable(

infrastructure/buckets.py:7

  • [nitpick] Renaming production_data_bucket to data_bucket enhances clarity; please ensure that all references to this bucket are updated.
data_bucket = storage.Bucket(

application/datamanager/src/datamanager/config.py:16

  • Updating the environment variable key from DATA_BUCKET to DATA_BUCKET_NAME ensures consistency across the project; confirm that the expectation in error messages remains accurate.
    name: str = Field(default=os.getenv("DATA_BUCKET_NAME", ""))

.mise.toml:93

  • The explicit stack flag clarifies deployment targeting; ensure the stack name matches the intended production environment.
uv run pulumi up --yes --stack pocketsizefund/pocketsizefund/production

.github/workflows/lifecycle.yaml:22

  • Refactoring the workflow to use 'mise tasks run' improves consistency; double-check that the corresponding task definitions are correctly updated.
          command: mise tasks run infrastructure:up

@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented Jun 22, 2025

Graphite Automations

"Assign author to pull request" took an action on this PR • (06/22/25)

1 assignee was added to this PR based on John Forstmeier's automation.

@graphite-app graphite-app Bot requested a review from chrisaddy June 22, 2025 03:21
@forstmeier forstmeier added this to the Refactor milestone Jun 22, 2025
@forstmeier forstmeier marked this pull request as draft June 23, 2025 00:20
@forstmeier forstmeier force-pushed the 06-21-infrastructure_updates_and_cleanup branch from c97e2bf to adcf666 Compare June 30, 2025 02:00
…:pocketsizefund/pocketsizefund into 06-21-infrastructure_updates_and_cleanup
@forstmeier forstmeier force-pushed the 06-21-infrastructure_updates_and_cleanup branch from adcf666 to a93307e Compare June 30, 2025 02:46
@forstmeier forstmeier marked this pull request as ready for review June 30, 2025 02:50
@forstmeier
Copy link
Copy Markdown
Collaborator Author

This is a ton of slop but it needs to be merged in both to get some of the services talking to each other (ideally) and to hit the June deadline. Most of this will need to be heavily reworked in the immediate future.

@forstmeier forstmeier merged commit 402b5b4 into master Jun 30, 2025
5 of 6 checks passed
@forstmeier forstmeier deleted the 06-21-infrastructure_updates_and_cleanup branch June 30, 2025 02:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants